package base

import (
	"context"
	"github.com/go-playground/form/v4"
	jsoniter "github.com/json-iterator/go"
	"github.com/zeromicro/go-zero/core/logc"
	"github.com/zeromicro/go-zero/rest"
	"io"
	"mime"
	"net/http"
	"payme3000/framework/config_center"
	"payme3000/framework/errorx"
)

type (
	// IRouter 路由处理器
	IRouter interface {
		IComponent
		Groups() []RouteGroup
	}

	// Router IRouter的基础实现
	Router struct {
		Component

		AppConf      *AppConf                    // 启动配置
		ConfigCenter *config_center.ConfigCenter // 配置中心

		Decoder           *form.Decoder
		MaxFormSize       int64
		ResponseHandle    func(ctx context.Context, w http.ResponseWriter, rsp any, err error)
		RequestProcessors []func(ctx context.Context, req any) error
	}

	// RouteGroup 路由群组
	RouteGroup struct {
		Routes  []rest.Route       // 提交给go-zero注册的路由
		Options []rest.RouteOption // 路由选项
	}
)

func (r *Router) Init(ctx context.Context) {
	r.Component.Init(ctx)
	r.Decoder = form.NewDecoder()
	r.MaxFormSize = int64(1<<63 - 1)
}

// Handle 处理请求
func (r *Router) Handle(
	w http.ResponseWriter,
	hr *http.Request,
	req any,
	handle func(context.Context) (any, error),
) {
	ctx := hr.Context()

	// POST请求尝试使用json解析请求参数
	ct, _, _ := mime.ParseMediaType(hr.Header.Get("Content-Type"))
	if hr.Method == "POST" && ct == "application/json" {
		bBody, err := io.ReadAll(io.LimitReader(hr.Body, r.MaxFormSize))
		if err != nil {
			errorx.Catch(ctx, err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		if int64(len(bBody)) > r.MaxFormSize {
			_ = errorx.Errorf(ctx, "http: POST too large with maxFormSize:%d, len(bBody):%d", r.MaxFormSize, len(bBody))
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		if err := jsoniter.Unmarshal(bBody, req); err != nil {
			errorx.Catch(ctx, err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}

	// 解析请求参数
	if err := hr.ParseForm(); err != nil {
		errorx.Catch(ctx, err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// 解码
	if err := r.Decoder.Decode(req, hr.Form); err != nil {
		errorx.Catch(ctx, err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// 请求处理前置处理
	for _, processor := range r.RequestProcessors {
		if err := processor(ctx, req); err != nil {
			errorx.Catch(ctx, err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}

	// 执行请求
	rsp, err := handle(context.WithoutCancel(ctx))
	if err != nil {
		logc.Errorf(ctx, "handle router error with err:%s, url:%s, req:%+v, rsp:%+v", err, hr.URL.String(), req, rsp)
	} else {
		logc.Infof(ctx, "handle router success with url:%s, req:%+v, rsp:%+v", hr.URL.String(), req, rsp)
	}

	// 返回响应
	r.ResponseHandle(ctx, w, rsp, err)
}
